﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Xml;

namespace IURIP
{
    /// <summary>
    /// It is used to build a data structure for StringTemplate from XML since HashTable can not be recognized in StringTemplate.
    /// </summary>
    public class StringHash
    {
        protected Hashtable m_children = new Hashtable();
        /// <summary>
        /// Adds a new item or updates an exists item
        /// </summary>
        /// <param name="key"></param>
        /// <param name="val"></param>
        public void Add(string key, object val)
        {
            if (!m_children.ContainsKey(key))
            {
                m_children.Add(key, val);
            }
            else
            {
                m_children[key] = val;
            }
        }
        /// <summary>
        /// Removes an exists item
        /// </summary>
        /// <param name="key"></param>
        public void Remove(string key)
        {
            if (m_children.ContainsKey(key))
            {
                m_children.Remove(key);
            }
        }
        /// <summary>
        /// Gets the specified item
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public object this[string key]
        {
            get { return m_children[key]; }
            set
            {
                if (m_children.Contains(key))
                {
                    m_children[key] = value;
                }
                else
                {
                    m_children.Add(key, value);
                }
            }
        }
        /// <summary>
        /// Converts XML data into StringHash in order to use StringTemplate
        /// </summary>
        /// <param name="xml">XML data</param>
        /// <param name="xmlEncode">need xml Encode or not</param>
        /// <param name="includeRoot">need include the xml root node in StringHash or not</param>
        /// <returns></returns>
        public static StringHash ConvertXMLStructure(string xml, bool xmlEncode = false, bool includeRoot = false)
        {
            StringHash res = new StringHash();
            XmlDocument doc = new XmlDocument();
            xml = includeRoot ? ("<data>" + xml + "</data>")  : xml;
            doc.LoadXml(xml);
            XmlNodeList fl = doc.SelectNodes("*/field");
            CreateFields(res, fl, xmlEncode);
            XmlNodeList ll = doc.SelectNodes("*/list");
            CreateList(res, ll, xmlEncode);
            return res;
        }
        private static void CreateFields(StringHash sh, XmlNodeList fields, bool xmlEncode)
        {
            for (int i = 0; i < fields.Count; i++)
            {
                LogicField tmp = new LogicField(fields[i].Attributes["name"].Value, xmlEncode ? System.Security.SecurityElement.Escape(fields[i].Attributes["value"].Value) : fields[i].Attributes["value"].Value);
                sh.Add(tmp.Name, tmp);
            }
        }
        private static void CreateList(StringHash sh, XmlNodeList lists, bool xmlEncode)
        {
            for (int i = 0; i < lists.Count; i++)
            {
                XmlNodeList sub = lists[i].SelectNodes("./listItem");
                LogicList list = new LogicList(lists[i].Attributes["name"].Value);
                for (int j = 0; j < sub.Count; j++)
                {
                    XmlNodeList flds = sub[j].SelectNodes("./field");
                    StringHash tmp = new StringHash();
                    CreateFields(tmp, flds, xmlEncode);
                    list.Add(tmp);
                    XmlNodeList lsts = sub[j].SelectNodes("./list");
                    CreateList(tmp, lsts, xmlEncode);
                }

                sh.Add(list.Name, list);
            }
        }

        private void Test()
        {
            string xml = @"<field name='a' value='b'></field>";
            var sh = ConvertXMLStructure(xml, false, true);
            Console.WriteLine(sh["a"]);
        }
    }

    public class LogicField : StringHash
    {
        public LogicField()
        {
        }
        public LogicField(string name, string val)
        {
            Name = name;
            Value = val;
        }
        public string Name;
        public string Value;
        public override string ToString()
        {
            return Value;
        }
    }
    public class LogicList : List<StringHash>
    {
        public LogicList()
        {
        }
        public LogicList(string name)
        {
            Name = name;
        }
        public string Name;
    }
}
